package com.linchuansi.framework;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.*;

public class AnnotationApplicationContext {
    private Map<String,Object> singletonObjects = new HashMap<>();
    private Map<String,BeanDefinition> beanDefinitionMap = new HashMap<>();
    public AnnotationApplicationContext(Class<?> clazz){
        CommentScan commentScanAnnotation = clazz.getAnnotation(CommentScan.class);
        if(commentScanAnnotation!=null) {
            String value = commentScanAnnotation.value();
            System.out.println("commentScanValue=" + value);
            List<Class<?>> classes = scanClass(value);
            for(String beanName:beanDefinitionMap.keySet())
            {
                BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
                if (beanDefinition.getScope().equals("singleton") && !beanDefinition.isLazy()) {
                    Object bean = createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, bean);
                }
            }
        }
    }
    private List<Class<?>> scanClass(String packageName)
    {
        List<Class<?>> classes = new ArrayList<>();
        try {
            // 将包名转换为路径
            String packagePath = packageName.replace('.', '/');
            ClassLoader classLoader= AnnotationApplicationContext.class.getClassLoader();
            Enumeration<URL> resources = classLoader.getResources(packagePath);
            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                System.out.println("资源=="+resource.getFile());
                File directory = new File(resource.getFile());
                if (directory.exists()) {
                    scanDirectory(directory, packageName, classes);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return classes;
    }
    private void scanDirectory(File directory, String packageName, List<Class<?>> classes) {
        File[] files = directory.listFiles();
        if (files != null) {
            for (File file : files) {
                if (file.isDirectory()) {
                    // 递归扫描子目录
                    scanDirectory(file, packageName + "." + file.getName(), classes);
                } else if (file.getName().endsWith(".class")) {
                    // 加载类文件
                    System.out.println("file="+file.getName());
                    String className = packageName + "." + file.getName().substring(0, file.getName().length() - 6);
                    System.out.println("className="+className);
                    try {
                        Class<?> clazz = Class.forName(className);
                        Comment commentAnnotation = clazz.getAnnotation(Comment.class);
                        if(commentAnnotation!=null) {
                            String beanName = commentAnnotation.value();
                            if("".equals(beanName))
                            {
                                beanName=clazz.getSimpleName();
                                if (className.length() > 0) {
                                    beanName= Character.toLowerCase(beanName.charAt(0)) + beanName.substring(1);
                                }
                            }
                            BeanDefinition beanDefinition = new BeanDefinition();
                            beanDefinition.setType(clazz);
                            Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
                            if(scopeAnnotation!=null && scopeAnnotation.value().equals(BeanScope.PROTOTYPE.getCode())) {
                                beanDefinition.setScope(BeanScope.PROTOTYPE.getCode());
                            }
                            else {
                                beanDefinition.setScope(BeanScope.SINGLETON.getCode());
                            }
                            Lazy lazyAnnotation = clazz.getAnnotation(Lazy.class);
                            if(lazyAnnotation!=null)
                            {
                                beanDefinition.setLazy(true);
                            }
                            beanDefinitionMap.put(beanName,beanDefinition);

                        }
                        classes.add(clazz);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    public Object getBean(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition ==null)
        {
            throw new RuntimeException("beanName="+beanName+"不存在");
        }
        if(beanDefinition.getScope().equals(BeanScope.SINGLETON.getCode()))
        {
            Object o = singletonObjects.get(beanName);
            if(o==null)
            {
                o=createBean(beanName,beanDefinition);
                return o;
            }
            return o;

        }
        else {
            return createBean(beanName,beanDefinition);
        }

    }
    private Object createBean(String beanName,BeanDefinition beanDefinition)
    {
        Class<?> clazz = beanDefinition.getType();
        Object o=null ;
        try
        {
            o =clazz.getDeclaredConstructor().newInstance();
            if( o instanceof BeanNameAware)
            {
                BeanNameAware beanNameAware = (BeanNameAware) o;
                beanNameAware.setBeanName(beanName);
            }
            Field[] declaredFields = clazz.getDeclaredFields();
            for (Field field : declaredFields) {
                Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);
                if(autowiredAnnotation!=null)
                {
                    System.out.println("field="+field.getName());
                    String autoValue = autowiredAnnotation.value();
                    System.out.println("autoValue="+autoValue);
                    Object bean = getBean(field.getName());
                    field.setAccessible(true);
                    field.set(o,bean);
                }
                if(field.isAnnotationPresent(Value.class))
                {
                    Value valueAnnotation = field.getAnnotation(Value.class);
                    String value = valueAnnotation.value();
                    field.setAccessible(true);
                    field.set(o,value);
                }
            }


        }
        catch (Exception e)
        {

        }
        return o;
    }
}